/**
    Copyright (c) 2010 yakiimo02
    Distributed under the New BSD License.
    See included license.txt or http://www.yakiimo3d.com/NewBSDLicense.txt
**/

#include "DXUT.h"
#include "GUI.h"
#include "BuddhabrotMgr.h"
#include "ToneMapCS.h"

// buddhabrot stuff
#define IDC_BUDDHABROT_MODE_CB                                10000
#define IDC_BUDDHABROT_ITERATION_R_TEXT                        10001
#define IDC_BUDDHABROT_ITERATION_R_SLIDER                    10002
#define IDC_BUDDHABROT_ITERATION_G_TEXT                        10003
#define IDC_BUDDHABROT_ITERATION_G_SLIDER                    10004
#define IDC_BUDDHABROT_ITERATION_B_TEXT                        10005
#define IDC_BUDDHABROT_ITERATION_B_SLIDER                    10006

// tonemap stuff
#define IDC_MIDDLEKEY_TEXT                20001
#define IDC_MIDDLEKEY_SLIDER            20002
#define IDC_TONEMAP_ENABLE_CB            20003
#define IDC_CONTROL_BURNOUT_CB            20004
#define MIDDLEKEY_SLIDER_MAX            1000

GUI g_gui;

void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void* pUserContext );

/**
*/
GUI::GUI() : m_pTxtHelper( NULL ), m_bDisplayGUI( true ), m_pModeCB( NULL ), 
             m_pMaxIterationSliderR( NULL ), m_pMaxIterationSliderG( NULL ), m_pMaxIterationSliderB( NULL ), 
             m_pMiddleKeySlider( NULL ), m_pToneMapEnableCheckBox( NULL ), m_pControlBurnOutCheckBox( NULL )
{
}

/**
    @param pd3dDevice    [in]    D3D Device
*/
HRESULT GUI::Create( ID3D11Device* pd3dDevice )
{
    HRESULT hr = S_OK;

    ID3D11DeviceContext* pd3dImmediateContext = DXUTGetD3D11DeviceContext();
    V_RETURN( m_DialogResourceManager.OnD3D11CreateDevice( pd3dDevice, pd3dImmediateContext ) );
    m_pTxtHelper = new CDXUTTextHelper( pd3dDevice, pd3dImmediateContext, &m_DialogResourceManager, 15 );

     return hr;
}

/**
*/
void GUI::RegistGuiItems()
{
    m_SampleUI.Init( &m_DialogResourceManager );

    int nY = 0;

    /** buddhabrot stuff */

    // mode combobox
    m_SampleUI.AddComboBox( IDC_BUDDHABROT_MODE_CB, 0, nY, 150, 24, 'M', false, &m_pModeCB );
    m_pModeCB->AddItem( L"CPU", IntToPtr(BUDDHABROT_MODE_CPU) );
    m_pModeCB->AddItem( L"ComputeShader", IntToPtr(BUDDHABROT_MODE_CS) );
    m_pModeCB->SetSelectedByIndex( g_buddhabrotMgr.GetMode() );
    m_pModeCB->SetTextColor( D3DCOLOR_XRGB( 0, 0, 255 ) );
    nY += 24;

    // iteration textbox and slider RED
    m_SampleUI.AddStatic( IDC_BUDDHABROT_ITERATION_R_TEXT, L"Max Iterations Red", 0, nY, 150, 24 );
    nY += 24;
    m_SampleUI.AddSlider( IDC_BUDDHABROT_ITERATION_R_SLIDER, 0, nY, 128, 15, 0, 50000, g_buddhabrotMgr.GetnMaxIterations( 0 ), false,  &m_pMaxIterationSliderR );
    m_pMaxIterationSliderR->SetValue( g_buddhabrotMgr.GetnMaxIterations( 0 ) );
    nY += 24;

    // iteration textbox and slider GREEN
    m_SampleUI.AddStatic( IDC_BUDDHABROT_ITERATION_G_TEXT, L"Max Iterations Green", 0, nY, 150, 24 );
    nY += 24;
    m_SampleUI.AddSlider( IDC_BUDDHABROT_ITERATION_G_SLIDER, 0, nY, 128, 15, 0, 50000, g_buddhabrotMgr.GetnMaxIterations( 1 ), false,  &m_pMaxIterationSliderG );
    m_pMaxIterationSliderG->SetValue( g_buddhabrotMgr.GetnMaxIterations( 1 ) );
    nY += 24;

    // iteration textbox and slider BLUE
    m_SampleUI.AddStatic( IDC_BUDDHABROT_ITERATION_B_TEXT, L"Max Iterations Blue", 0, nY, 150, 24 );
    nY += 24;
    m_SampleUI.AddSlider( IDC_BUDDHABROT_ITERATION_B_SLIDER, 0, nY, 128, 15, 0, 50000, g_buddhabrotMgr.GetnMaxIterations( 2 ), false,  &m_pMaxIterationSliderB );
    m_pMaxIterationSliderB->SetValue( g_buddhabrotMgr.GetnMaxIterations( 2 ) );
    nY += 24;

    /** tonemapping stuff */

    // enable tonemapping checkbox
    m_SampleUI.AddCheckBox( IDC_TONEMAP_ENABLE_CB, L"Tone Mapping", 0, nY, 0, 24, g_toneMapCS.GetToneMapEnable(), 'T', false, &m_pToneMapEnableCheckBox );
    m_pToneMapEnableCheckBox->SetTextColor( D3DCOLOR_XRGB( 0, 0, 255 ) );
    nY += 24;

    // enable control burnout checkbox
    m_SampleUI.AddCheckBox( IDC_CONTROL_BURNOUT_CB, L"Control BurnOut", 0, nY, 0, 24, g_toneMapCS.GetControlBurnOut(), 'B', false, &m_pControlBurnOutCheckBox );
    m_pToneMapEnableCheckBox->SetTextColor( D3DCOLOR_XRGB( 0, 0, 255 ) );
    nY += 24;
    
    // middle key slider
    m_SampleUI.AddStatic( IDC_MIDDLEKEY_TEXT, L"Middle Key", 0, nY, 150, 24 );
    nY += 24;
    m_SampleUI.AddSlider( IDC_MIDDLEKEY_SLIDER, 0, nY, 128, 24, 0, MIDDLEKEY_SLIDER_MAX, 55, false, &m_pMiddleKeySlider );
    SetMiddleKeyValue();
    nY += 24;

    m_SampleUI.SetCallback( OnGUIEvent ); 
}

/**
    @param fElapsedTime        [in]        elapsed time
*/
void GUI::FrameRender( float fElapsedTime )
{
    if( m_bDisplayGUI ) {
        m_SampleUI.OnRender( fElapsedTime );
        RenderText();
    }
}

/**
*/
void GUI::RenderText()
{
    wchar_t strMsg[ 256 ];

    m_pTxtHelper->Begin();
    m_pTxtHelper->SetInsertionPos( 2, 0 );
    m_pTxtHelper->SetForegroundColor( D3DXCOLOR( 1.0f, 0.0f, 0.0f, 1.0f ) );
    m_pTxtHelper->DrawTextLine( DXUTGetFrameStats( DXUTIsVsyncEnabled() ) );
    m_pTxtHelper->DrawTextLine( DXUTGetDeviceStats() );

    // mandelbrot basic information
    const float fScale    = g_buddhabrotMgr.GetfZoomScale();
    const ConstantBuf* pConstantBuf = g_buddhabrotMgr.GetpConstantBuf();
    swprintf_s( strMsg, L"Real: <%f,%f> Img: <%f,%f> Scale: %f", pConstantBuf->fMinRe, pConstantBuf->fMaxRe, pConstantBuf->fMinIm, pConstantBuf->fMaxIm, fScale );
    m_pTxtHelper->DrawTextLine( strMsg );

    float fFPS = DXUTGetFPS();
    float fSamplesPerSecond = fFPS*BUDDHABROT_SAMPLES_PER_FRAME;

    // iteration    
    swprintf_s( strMsg, L"Iteration RGB: <%d,%d,%d> SamplesPerSecond: %f", pConstantBuf->maxIterations[ 0 ], pConstantBuf->maxIterations[ 1 ], pConstantBuf->maxIterations[ 2 ], fSamplesPerSecond );
    m_pTxtHelper->DrawTextLine( strMsg );

    // tonemap
    const MeasureLuminanceCS* pMeasureLuminanceCS = g_toneMapCS.GetpMeasureLuminanceCS();
    swprintf_s( strMsg, L"MiddleKey: %f LogAvgLum: %f LumMax: %f", g_toneMapCS.GetMiddleKey(), pMeasureLuminanceCS->GetLogAvgLum(), pMeasureLuminanceCS->GetLumMax() );
    m_pTxtHelper->DrawTextLine( strMsg );

    // demo instructions
    swprintf_s( strMsg, L"Translate: Left-Ctrl+LMB, Zoom: Left-Ctrl+RMB, Hide GUI: H key" );
    m_pTxtHelper->DrawTextLine( strMsg );

    m_pTxtHelper->End();
}

/**
    @param pd3dDevice        [in]    D3D Device
    @param pBackBufferDesc    [in]    Description of backbuffer
*/
HRESULT GUI::ResizedSwapChain( ID3D11Device* pd3dDevice, const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc )
{
    HRESULT hr = S_OK;
    V_RETURN( m_DialogResourceManager.OnD3D11ResizedSwapChain( pd3dDevice, pBackBufferSurfaceDesc ) );

    m_SampleUI.SetLocation( pBackBufferSurfaceDesc->Width - 170, pBackBufferSurfaceDesc->Height - 280 );
    m_SampleUI.SetSize( 150, 110 );

    return hr;
}

/**
*/
void GUI::Destroy()
{
    m_DialogResourceManager.OnD3D11DestroyDevice();
    SAFE_DELETE( m_pTxtHelper );    
}

/**
*/
LRESULT GUI::MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing )
{
    // Pass messages to dialog resource manager calls so GUI state is updated correctly
    *pbNoFurtherProcessing = m_DialogResourceManager.MsgProc( hWnd, uMsg, wParam, lParam );
    if( *pbNoFurtherProcessing )
        return 0;

    *pbNoFurtherProcessing = m_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );
    if( *pbNoFurtherProcessing )
        return 0;    

    return 0;
}

/**
    CDXUTDialog callback.
*/
void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void* pUserContext )
{
    switch( nControlID )
    {
    case IDC_BUDDHABROT_MODE_CB:
        {
            CDXUTComboBox* pComboBox = ( CDXUTComboBox* )pControl;
            g_buddhabrotMgr.SetMode( static_cast< BuddhabrotMode >( PtrToInt( pComboBox->GetSelectedData() ) ) );
            break;
        }

    case IDC_BUDDHABROT_ITERATION_R_SLIDER:
        {
            CDXUTSlider* pSlider = ( CDXUTSlider* )pControl;
            g_buddhabrotMgr.SetnMaxIterations( 0, pSlider->GetValue() );
            break;
        }

    case IDC_BUDDHABROT_ITERATION_G_SLIDER:
        {
            CDXUTSlider* pSlider = ( CDXUTSlider* )pControl;
            g_buddhabrotMgr.SetnMaxIterations( 1, pSlider->GetValue() );
            break;
        }

    case IDC_BUDDHABROT_ITERATION_B_SLIDER:
        {
            CDXUTSlider* pSlider = ( CDXUTSlider* )pControl;
            g_buddhabrotMgr.SetnMaxIterations( 2, pSlider->GetValue() );
            break;
        }

    // tonemap stuff
    case IDC_MIDDLEKEY_SLIDER:
        {
            //CDXUTSlider* pSlider = ( CDXUTSlider* )pControl;
            g_gui.SetMiddleKeyValue();
            break;
        }

    case IDC_TONEMAP_ENABLE_CB:
        {
            CDXUTCheckBox* pCheckBox = ( CDXUTCheckBox* )pControl;
            g_toneMapCS.SetToneMapEnable( pCheckBox->GetChecked() );
            break;
        }

    case IDC_CONTROL_BURNOUT_CB:
        {
            CDXUTCheckBox* pCheckBox = ( CDXUTCheckBox* )pControl;
            g_toneMapCS.SetControlBurnOut( pCheckBox->GetChecked() );
            break;
        }
    }
}

/**
*/
void GUI::SetMiddleKeyValue()
{
    g_toneMapCS.SetMiddleKey( ( 1.0f*m_pMiddleKeySlider->GetValue() )/MIDDLEKEY_SLIDER_MAX );
}
